package service

import (
	"context"
	"encoding/json"
	"fx_swift_ifcgate/api"
	"fx_swift_ifcgate/internal/model"
	"fx_swift_ifcgate/pkg/code"
	"fx_swift_ifcgate/pkg/global"
	"fx_swift_ifcgate/pkg/internalerrors"
	"fx_swift_ifcgate/pkg/logger"
	"fx_swift_ifcgate/pkg/page"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/spf13/cast"
)

// 国内/国际收款人
type IPayeeSrv interface {
	OperatorDomesticPayee(ctx context.Context, req *api.OperatorPayeeReq) error

	QueryPayeeDomesticInfo(ctx context.Context, req *api.QueryOperatorPayeeReq) (*page.Collection[*api.QueryOperatorPayeeRes], error)

	PayeeDomesticDetails(ctx context.Context, id string) (*api.PayeeDomesticDetailsRes, error)

	OperatorPayeeInternation(ctx context.Context, req *api.OperatorPayeeInternationReq) error

	PayeeInternationDetails(ctx context.Context, id string) (*api.PayeeInternationDetailsRes, error)

	PayeeInternationDel(ctx context.Context, id string) error

	PayeeInternationList(ctx context.Context, req *api.PayeeInternationListReq) (*page.Collection[*api.PayeeInternationListRes], error)

	PayeePostTp3005(ctx context.Context, req *api.PayeePostTp3005Req) (*api.AutoGenerated, error)
}

type payeeSrv struct {
}

func NewPayeeSrv() IPayeeSrv {
	return &payeeSrv{}
}

// 结汇收款人(针对国内或者国际中的本地银行)
func (e *payeeSrv) OperatorDomesticPayee(ctx context.Context, req *api.OperatorPayeeReq) error {
	var (
		err                        error
		merchantNo                 string
		tp1021Res                  *api.Tp1021Res
		tp1022Res                  *api.Tp1022Res
		tp1023Res                  *api.Tp1023Res
		merchantInfo               *model.IFCGateMerChantVAInfo
		vaInfo                     *model.IFCGateVAInfoCallBack
		SupplementaryMaterialsPath string
		LegalBackCardPath          string
		LegalFrontCardPath         string
		BackCardPath               string
		FrontCardPath              string
		BusinessLicensePath        string
		merchantToken              string
		redisResult                *gvar.Var
	)
	merchantNo = ctx.Value("MerchantNo").(string)

	redisResult, err = g.Redis().Get(ctx, merchantNo)
	if err != nil || redisResult.IsEmpty() {
		return internalerrors.New(code.ErrUnknown, "获取商户号对应的token失败")
	}
	merchantToken = redisResult.String()

	if len(req.SupplementaryMaterialsPath) > 0 {
		SupplementaryMaterialsPath = OperatorImageToSftp(req.SupplementaryMaterialsPath)
	}
	if len(req.LegalBackCardPath) > 0 {
		LegalBackCardPath = OperatorImageToSftp(req.LegalBackCardPath)
	}
	if len(req.LegalFrontCardPath) > 0 {
		LegalFrontCardPath = OperatorImageToSftp(req.LegalFrontCardPath)
	}
	if len(req.BackCardPath) > 0 {
		BackCardPath = OperatorImageToSftp(req.BackCardPath)
	}
	if len(req.FrontCardPath) > 0 {
		FrontCardPath = OperatorImageToSftp(req.FrontCardPath)
	}
	if len(req.BusinessLicensePath) > 0 {
		BusinessLicensePath = OperatorImageToSftp(req.BusinessLicensePath)
	}
	if req.Method == "add" {
		if err = global.GFDB.Model("ifcgate_merchant_va_info").
			Where("merchant_no=?", merchantNo).Scan(&merchantInfo); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if err = global.GFDB.Model("ifcgate_vainfo_call_back").
			Where("merchant_no=?", merchantNo).Scan(&vaInfo); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		objs := &api.Tp1021Req{
			Currency:                   req.Currency,
			Country:                    req.Country,
			BranchName:                 req.BranchName,
			BankAcctNo:                 req.BankAcctNo,
			Mobile:                     req.Mobile,
			PayeeName:                  req.PayeeName,
			BankCode:                   req.BankCode,
			PayeeType:                  req.PayeeType,
			SubjectType:                req.SubjectType,
			CertNo:                     req.CertNo,
			BusinessType:               req.BusinessType,
			SupplementaryMaterialsPath: SupplementaryMaterialsPath,
			LegalBackCardPath:          LegalBackCardPath,
			LegalFrontCardPath:         LegalFrontCardPath,
			LegalCertNo:                req.LegalCertNo,
			BackCardPath:               BackCardPath,
			FrontCardPath:              FrontCardPath,
			BusinessLicensePath:        BusinessLicensePath,
		}
		tp1021Res, err = PostTp1021(objs, merchantToken)
		if err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if tp1021Res.Body.Code == "FAIL" {
			return internalerrors.New(code.ErrUnknown, "新增失败")
		}
		if _, err = global.GFDB.Insert(ctx, "ifcgate_domestic_payee", &model.IfcgateDomesticPayee{
			BizFlow:                    tp1021Res.Body.BizFlow,
			MerchantNo:                 merchantNo,
			SubjectType:                req.SubjectType,
			PayeeName:                  req.PayeeName,
			CertNo:                     req.CertNo,
			Mobile:                     req.Mobile,
			Country:                    req.Country,
			BankCode:                   req.BankCode,
			Currency:                   req.Currency,
			BankAcctNo:                 req.BankAcctNo,
			BranchName:                 req.BranchName,
			BusinessType:               req.BusinessType,
			PayeeType:                  req.PayeeType,
			SupplementaryMaterialsPath: req.SupplementaryMaterialsPath,
			BusinessLicensePath:        req.BusinessLicensePath,
			FrontCardPath:              req.FrontCardPath,
			BackCardPath:               req.BackCardPath,
			LegalFrontCardPath:         req.LegalFrontCardPath,
			LegalBackCardPath:          req.LegalBackCardPath,
			LegalCertNo:                req.LegalCertNo,
			Status:                     model.ErrorCodToString(tp1021Res.Body.Status),
			SenderName:                 vaInfo.AccountName,
			SenderIncorporationNo:      merchantInfo.CompanyCertificateNumber,
			RegistrationRegion:         vaInfo.Area,
			SenderBankName:             vaInfo.BankName,
		}); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	} else if req.Method == "update" {
		objs := &api.Tp1022Req{
			BizFlow:                    req.BizFlow,
			Country:                    req.Country,
			BankAcctNo:                 req.BankAcctNo,
			PayeeType:                  req.PayeeType,
			Mobile:                     req.Mobile,
			BranchName:                 req.BranchName,
			SubjectType:                req.SubjectType,
			CertNo:                     req.CertNo,
			PayeeName:                  req.PayeeName,
			Currency:                   req.Currency,
			BankCode:                   req.BankCode,
			BusinessType:               req.BusinessType,
			SupplementaryMaterialsPath: SupplementaryMaterialsPath,
			LegalBackCardPath:          LegalBackCardPath,
			LegalFrontCardPath:         LegalFrontCardPath,
			LegalCertNo:                req.LegalCertNo,
			BackCardPath:               BackCardPath,
			FrontCardPath:              FrontCardPath,
			BusinessLicensePath:        BusinessLicensePath,
		}
		tp1022Res, err = PostTp1022(objs, merchantToken)
		if err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if tp1022Res.Body.Code == "FAIL" {
			return internalerrors.New(code.ErrUnknown, "修改失败")
		}
		if _, err = global.GFDB.Model("ifcgate_domestic_payee").Data(g.Map{
			"subject_type": req.SubjectType, "payee_name": req.PayeeName,
			"cert_no": req.CertNo, "mobile": req.Mobile,
			"country": req.Country, "currency": req.Currency,
			"bank_acct_no": req.BankAcctNo, "branch_name": req.BranchName,
			"business_type": req.BusinessType, "payee_type": req.PayeeType,
			"supplementary_materials_path": req.SupplementaryMaterialsPath,
			"business_license_path":        req.BusinessLicensePath,
			"front_card_path":              req.FrontCardPath,
			"back_card_path":               req.BackCardPath,
			"legal_front_card_path":        req.LegalFrontCardPath,
			"legal_back_card_path":         req.LegalBackCardPath,
			"legal_cert_no":                req.LegalCertNo,
			"bank_code":                    req.BankCode,
		}).
			Where("id=?", req.Id).
			Update(); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	} else if req.Method == "del" {
		tp1023Res, err = PostTp1023(&api.Tp1023Req{
			BizFlow: req.BizFlow,
		}, merchantToken)
		if err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if tp1023Res.Body.Code == "FAIL" {
			return internalerrors.New(code.ErrUnknown, "删除失败")
		}
		if _, err = global.GFDB.Model("ifcgate_domestic_payee").Where("id=?", req.Id).Delete(); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}

// 查询结汇收款人信息
func (e *payeeSrv) QueryPayeeDomesticInfo(ctx context.Context, req *api.QueryOperatorPayeeReq) (*page.Collection[*api.QueryOperatorPayeeRes], error) {
	var (
		err        error
		total      int
		merchantNo string
		resultList []*api.QueryOperatorPayeeRes
	)

	collectionDto := &page.Collection[*api.QueryOperatorPayeeRes]{}
	collectionDto.Page = uint64(req.PageNo)
	collectionDto.PageSize = uint64(req.PageSize)

	merchantNo = ctx.Value("MerchantNo").(string)
	if len(merchantNo) > 0 {
		mod := global.GFDB.Ctx(ctx).Model("ifcgate_domestic_payee")
		if len(req.Mobile) > 0 {
			mod.Where("mobile=?", req.Mobile)
		}
		if len(req.BankAcctNo) > 0 {
			mod.Where("bank_acct_no=?", req.BankAcctNo)
		}
		if len(req.Currency) > 0 {
			mod.Where("currency=?", req.Currency)
		}
		if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
			mod.Where("created_at >=? and created_at <= ?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
		}
		mod.Where("merchant_no=?", merchantNo)
		mod.Order("created_at desc")
		mod.Limit(int(page.PageToOffset(uint64(req.PageNo), uint64(req.PageSize))), cast.ToInt(req.PageSize))
		err = mod.ScanAndCount(&resultList, &total, false)
		collectionDto.TotalPage = page.GetTotalPage(uint64(req.PageNo), uint64(req.PageSize), cast.ToInt64(total))
		if err != nil {
			return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
		}
		collectionDto.Total = cast.ToInt64(total)
		collectionDto.List = resultList
	}

	return collectionDto, err
}

// 查询结汇收款人详情
func (e *payeeSrv) PayeeDomesticDetails(ctx context.Context, id string) (*api.PayeeDomesticDetailsRes, error) {
	var (
		err    error
		result *api.PayeeDomesticDetailsRes
	)
	if err = global.GFDB.Ctx(ctx).
		Model("ifcgate_domestic_payee").Where("id=?", id).Scan(&result); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return result, err
}

// 国际汇款人
func (e *payeeSrv) OperatorPayeeInternation(ctx context.Context, req *api.OperatorPayeeInternationReq) error {
	var (
		err        error
		merchantNo string
	)
	merchantNo = ctx.Value("MerchantNo").(string)
	if len(req.Id) == 0 { // 新增
		if _, err = global.GFDB.Insert(ctx, "ifcgate_internation_payee", &model.IfcgateInternationPayee{
			MerchantNo:           merchantNo,
			SubjectType:          req.SubjectType,
			CountryCode:          req.CountryCode,
			PayeeFirstName:       req.PayeeFirstName,
			PayeeLastName:        req.PayeeLastName,
			PayeeCity:            req.PayeeCity,
			PayeeProvince:        req.PayeeProvince,
			PayeeIdNo:            req.PayeeIdNo,
			PayeeEmail:           req.PayeeEmail,
			PayeePhone:           req.PayeePhone,
			PayeeAddress:         req.PayeeAddress,
			PayeeZipCode:         req.PayeeZipCode,
			PayeeAcctType:        req.PayeeAcctType,
			PayeeBankName:        req.PayeeBankName,
			PayeeBankAccountNo:   req.PayeeBankAccountNo,
			PayeeBankAddress:     req.PayeeBankAddress,
			PayeeRegisterNo:      req.PayeeRegisterNo,
			PayeeResidentCountry: req.PayeeResidentCountry,
			PayeeBankSwift:       req.PayeeBankSwift,
			PayeeCompanyName:     req.PayeeCompanyName,
			ArriveCurrency:       req.ArriveCurrency,
			PayType:              req.PayType,
			BankAcctType:         req.BankAcctType,
			PayeeBankBranchCode:  req.PayeeBankBranchCode,
			PayerProvince:        req.PayerProvince,
			PayerPostalCode:      req.PayerPostalCode,
			Status:               "SUCCESS",
		}); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	} else {
		if _, err = global.GFDB.Ctx(ctx).Model("ifcgate_internation_payee").Data(
			g.Map{"subject_type": req.SubjectType, "country_code": req.CountryCode,
				"payee_first_name": req.PayeeFirstName, "payee_last_name": req.PayeeLastName,
				"payee_city": req.PayeeCity, "payee_province": req.PayeeProvince,
				"payee_id_no": req.PayeeIdNo, "payee_email": req.PayeeEmail,
				"payee_phone": req.PayeePhone, "payee_address": req.PayeeAddress,
				"payee_zip_code": req.PayeeZipCode, "payee_acct_type": req.PayeeAcctType,
				"payee_bank_name": req.PayeeBankName, "payee_bank_account_no": req.PayeeBankAccountNo,
				"payee_bank_address": req.PayeeBankAddress,
				"payee_register_no":  req.PayeeRegisterNo, "payee_resident_country": req.PayeeResidentCountry,
				"payee_company_name": req.PayeeCompanyName, "payee_bank_swift": req.PayeeBankSwift,
				"arrive_currency": req.ArriveCurrency, "pay_type": req.PayType,
				"bank_acct_type": req.BankAcctType, "payee_bank_branch_code": req.PayeeBankBranchCode,
				"payer_province": req.PayerProvince, "payer_postal_code": req.PayerPostalCode}).
			Where("id=?", req.Id).
			Update(); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}

// 国际收款人详情
func (e *payeeSrv) PayeeInternationDetails(ctx context.Context, id string) (*api.PayeeInternationDetailsRes, error) {
	var (
		err    error
		result *api.PayeeInternationDetailsRes
	)
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_internation_payee").Where("id=?", id).Scan(&result); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return result, err
}

// 删除国际收款人
func (e *payeeSrv) PayeeInternationDel(ctx context.Context, id string) error {
	var (
		err error
	)
	if _, err = global.GFDB.Ctx(ctx).Model("ifcgate_internation_payee").Where("id=?", id).Delete(); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	return err
}

// 国际汇款人列表
func (e *payeeSrv) PayeeInternationList(ctx context.Context, req *api.PayeeInternationListReq) (*page.Collection[*api.PayeeInternationListRes], error) {
	var (
		err        error
		total      int
		merchantNo string
		resultList []*api.PayeeInternationListRes
	)

	collectionDto := &page.Collection[*api.PayeeInternationListRes]{}
	collectionDto.Page = uint64(req.PageNo)
	collectionDto.PageSize = uint64(req.PageSize)

	merchantNo = ctx.Value("MerchantNo").(string)
	if len(merchantNo) > 0 {
		mod := global.GFDB.Ctx(ctx).Model("ifcgate_internation_payee")
		if len(req.PayeeBankAccountNo) > 0 {
			mod.Where("payee_bank_account_no like ?", "%"+req.PayeeBankAccountNo+"%")
		}
		if len(req.ArriveCurrency) > 0 {
			mod.Where("arrive_currency=?", req.ArriveCurrency)
		}
		mod.Where("merchant_no=?", merchantNo)
		mod.Order("created_at desc")
		mod.Limit(int(page.PageToOffset(uint64(req.PageNo), uint64(req.PageSize))), cast.ToInt(req.PageSize))
		err = mod.ScanAndCount(&resultList, &total, false)
		collectionDto.TotalPage = page.GetTotalPage(uint64(req.PageNo), uint64(req.PageSize), cast.ToInt64(total))
		if err != nil {
			return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
		}
		collectionDto.Total = cast.ToInt64(total)
		collectionDto.List = resultList
	}
	return collectionDto, err
}

// Tp3005接口
func (e *payeeSrv) PayeePostTp3005(ctx context.Context, req *api.PayeePostTp3005Req) (*api.AutoGenerated, error) {
	type OttPayParams struct {
		AccountType    string `json:"accountType"`
		ArriveCurrency string `json:"arriveCurrency"`
		CountryCode    string `json:"countryCode"`
		DebitCurrency  string `json:"debitCurrency"`
		PayType        string `json:"payType"`
	}
	var (
		err    error
		body   []byte
		resStr []byte
	)
	ottPayParams := OttPayParams{}
	ottPayParams.PayType = req.PayType
	ottPayParams.DebitCurrency = req.DebitCurrency
	ottPayParams.ArriveCurrency = req.ArriveCurrency
	ottPayParams.AccountType = "1"
	ottPayParams.CountryCode = req.CountryCode
	body, err = json.Marshal(&ottPayParams)
	resStr, err = OperatorParamToPost("tp3005", "", body)
	if err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	ottPayResult := &api.PayeePostTp3005Res{}
	err = json.Unmarshal(resStr, &ottPayResult)
	if err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return &ottPayResult.AutoGeneratedBody, err
}
